package org.etherframework.tests.features.mediation
{
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	
	import org.etherframework.IEther;
	import org.etherframework.controller.Controller;
	import org.etherframework.core.IModule;
	import org.etherframework.dependency.IDependencies;
	import org.etherframework.mediation.Mediations;
	import org.etherframework.tests.features.mediation.models.SampleModel;
	import org.etherframework.tests.features.mediation.providers.SampleProvider;
	import org.etherframework.tests.utils.ModuleInfo;
	import org.etherframework.tests.utils.TestUtility;
	import org.flexunit.async.Async;
	import org.fluint.uiImpersonation.UIImpersonator;
	import org.hamcrest.assertThat;
	import org.hamcrest.object.equalTo;
	import org.hamcrest.text.emptyString;
	
	import spark.components.Group;

	public class when_using_bind
	{	
		private static var _testUtility:TestUtility = new TestUtility();
		private static var _info:ModuleInfo;
		private static var _context:IModule;
		private static var _d:IDependencies;
		private static var _ether:IEther;
		private static var _moduleView:Group;
		
		[BeforeClass(async)]
		public static function setUpBeforeClass():void
		{
			_moduleView = UIImpersonator.addChild(new Group()) as Group;
			_info = _testUtility.createModuleInfo(null, _moduleView);
			_context = _info.module;
			_d = _info.module.dependencies;
			_ether = _info.module.ether;
			
			_d.addClass(SampleModel);
			_d.addClass(SampleProvider);
			
			const dispatcher:IEventDispatcher = Mediations.prepare([SampleModel, SampleProvider]);
			Async.proceedOnEvent(when_using_bind, dispatcher, Event.COMPLETE, 10000);
		}
		
		[AfterClass]
		public static function tearDownAfterClass():void
		{
			_testUtility.dispose();
			UIImpersonator.removeAllChildren();
		}
		
		[Test(order=1)]
		public function it_should_execute_setter_handler():void
		{
			//Arrange
			var value:String = "foo";
			var executedValue:String
			var model:SampleModel = _ether.dependencies.getInstance(SampleModel) as SampleModel;
			var handler:Function = function(value:String):void{ executedValue = value; };
			
			// We bind only setter here.
			_ether.mediations.bind.property(model.currentItem, handler);
			
			// Act
			// All setter handlers will be executed by framework.
			model.currentItem = value;
			
			// Assert
			assertThat(executedValue, equalTo(value));
		}
		
		[Test(order=2)]
		public function it_should_execute_getter_handler():void
		{
			//Arrange
			var originalValue:String;
			var getValue:String;
			var substitutedValue:String;
			var model:SampleModel = _ether.dependencies.getInstance(SampleModel) as SampleModel;
			var handler:Function = function():String{ return "foo"; };
			model.currentItem = "bar";

			// Act
			originalValue = model.currentItem;
			// We bind only getter here.
			_ether.mediations.bind.property(model.currentItem, null, handler);
			
			// As getters handlers are not substituted during normal "get" so we will 
			// have an original value even after setting binding for a property.
			getValue = model.currentItem;
			
			// When do "get" within binding execution framework substitutes getter 
			// handler result thus we will have a substituted value.
			_ether.mediations.execute.binding(substitutedValue = model.currentItem);
			
			// Assert
			assertThat(originalValue, equalTo("bar"));
			assertThat(getValue, equalTo("bar"));
			assertThat(substitutedValue, equalTo("foo"));
		}
		
		[Test(order=3)]
		public function it_should_execute_method_handler():void
		{
			//Arrange
			var executedValue:String;
			var executedWhenBound:String;
			var provider:SampleProvider = _ether.dependencies.getInstance(SampleProvider) as SampleProvider;
			var handler:Function = function(value:String):void{ executedValue = value; };
			_ether.mediations.bind.method(provider.updateSomethig(null), handler);
			
			// Act
			// Here we show that method was not executed during binding creation 
			// thus internal state of object was not changed.
			executedWhenBound = provider.updateSomethingExecuted;
			provider.updateSomethig("orange");			
			
			// Assert
			assertThat(executedWhenBound, emptyString());
			assertThat(provider.updateSomethingExecuted, equalTo("orange"));
		}
		
		[Test(order=4)]
		public function it_should_execute_method_handler_with_result():void
		{
			//Arrange
			var originalValue:String;
			var substitutedValue:String;
			var provider:SampleProvider = _ether.dependencies.getInstance(SampleProvider) as SampleProvider;
			var handler:Function = function():String{ return "anotherData"; };
			
			_ether.mediations.bind.method(provider.getCurentData(), handler);
			
			// Act
			originalValue = provider.getCurentData();
			_ether.mediations.execute.binding(substitutedValue = provider.getCurentData());
			
			// Assert
			assertThat(originalValue, equalTo("currentData"));
			assertThat(substitutedValue, equalTo("anotherData"));
			
			Controller;
		}
	}
}